#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <string.h>
#include <sstream>
#include <limits>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <utility>
#include <functional>
using namespace std;
typedef vector<short> vs;
typedef istream_iterator<char> iIterator;
typedef vector<short> Category;
typedef vector<short> Vshort;
typedef multimap<string, Category> Game;
const short bonus_score = 63;
const short bonus_points = 35;
const short max_score = 375;
short Scores[15];
stringstream oss(stringstream::in | stringstream::out);

struct cell {
	short weight;
	bool starred, primed;
	cell() {
		starred = false;
		primed = false;
		weight = -1;
	}
};

typedef pair<short, short> ordered_pair;

class munkres {
	public:
		munkres() { }
		~munkres() { }

		//assign a matching
		//returns the total weight of the matching
		//takes a pointer to integer as a parameter and this
		//will be the matching in the form of an array
		short assign(vector<ordered_pair>& matching) {
			short total_cost = 0;
			bool matching_found = false;
			matching_found = find_a_matching();
			for (short i = 0; i < num_rows; i++) {
				for (short j = 0; j < num_columns; j++) {
					if (cell_array[i][j].starred) {
						matching[i].second	= j;
						matching[i].first = i;
						total_cost += weight_array[i][j];
					}
				}
			}
			return total_cost;
		}

		//Load weight array from a vector of vectors of integers
		//Accepts an object of type vector< vector<int> >, which is
		//a matrix of any dimensions with integer values > -1
		void load_weights(std::vector< std::vector<short> > x) {	
			short a = x.size(), b = x[0].size();
			std::vector<short> ivector;
			cell default_cell;
			std::vector<cell> default_vector;
			if (a > b) {
				num_rows = b;
				num_columns = a;
				ivector.resize(num_columns, -1);
				weight_array.resize(num_rows, ivector);
				default_vector.resize(num_columns, default_cell);
				cell_array.resize(num_rows, default_vector);

				for (short i = 0; i < num_rows; i++) {
					for (short j = 0; j < num_columns; j++) {
						weight_array[i][j] = x[j][i];
						cell_array[i][j].weight = x[j][i];
					}
				}
			} else {
				num_rows = a;
				num_columns = b;
				ivector.resize(num_columns, -1);
				weight_array.resize(num_rows, ivector);
				default_vector.resize(num_columns, default_cell);
				cell_array.resize(num_rows, default_vector);

				for (short i = 0; i < num_rows; i++) {
					for (short j = 0; j < num_columns; j++) {
						weight_array[i][j] = x[i][j];
						cell_array[i][j].weight = x[i][j];
					}
				}
			}

			row_starred.resize(num_rows, false);
			row_cov.resize(num_rows, false);
			column_starred.resize(num_columns, false);
			column_cov.resize(num_columns, false);	
		}

	private:

		//Delimiters to show number of operable rows and columns
		//after the cell array is populated
		short num_rows;
		short num_columns;

		//arrays to keep track of which columns and rows have 
		//starred zeroes
		std::vector<bool> row_starred, column_starred; 

		//array to show which rows and columns are covered
		std::vector<bool> row_cov, column_cov;

		//The matrix operated on by Munkres' algorithm
		//(could be better than an array in the future)
		std::vector< std::vector<cell> > cell_array;

		//array to store the weights for calculating total weight
		std::vector< std::vector<short> > weight_array;

		//functions to check if there is a starred zero in the current row or column
		short find_star_column(short c) {
			for (short i = 0; i < num_rows; i++) {
				if (cell_array[i][c].starred == true) {
					column_starred[c] = true;
					row_starred[i] = true;
					return i;
				}
			}
			return -1;
		}

		short find_star_row(short r) {
			for (short i = 0; i < num_columns; i++) {
				if (cell_array[r][i].starred == true) {
					row_starred[r] = true;
					column_starred[i] = true;
					return i;
				}
			}
			return -1;
		}

		//functions to check if there is a primed zero in the current row or column
		short find_prime_column(short c) {
			for (short i = 0; i < num_rows; i++) {
				if (cell_array[i][c].primed == true) {
					return i;
				}
			}
			return -1;
		}

		short find_prime_row(short r) {
			for (short i = 0; i < num_columns; i++) {
				if (cell_array[r][i].primed == true) {
					return i;
				}
			}
			return -1;
		}

		//These are the declarations for Munkres' algorithm steps
		void step1() {
			short smallest = 0;
			for (short i = 0; i < num_rows; i++) {
				while (smallest == 0){
					smallest = cell_array[i][0].weight;
					if (smallest == 0) {
						if (i < num_rows-1)
							i++;
						else
							break;
					}
				}
				for (short j = 1; j < num_columns; j++) {	
					if (cell_array[i][j].weight == 0) {
						smallest = 0;
						j = num_columns;
					} else if (cell_array[i][j].weight < smallest) {
						smallest = cell_array[i][j].weight;
					}
				}

				if (smallest != 0) {
					for (short j = 0; j < num_columns; j++) {	
						cell_array[i][j].weight -= smallest;
					}
				}
				smallest = 0;
			}
		}
		
		void step2() {
			for (short i = 0; i < num_rows; i++) {
				for (short j = 0; j < num_columns; j++) {
					if (cell_array[i][j].weight == 0) {
						if (!row_starred[i]) {
							find_star_row(i);
						}

						if (!column_starred[j]) {
							find_star_column(j);
						}

						if (!row_starred[i] && !column_starred[j]) {
							cell_array[i][j].starred = true;
							row_starred[i] = true;
							column_starred[j] =  true;
						}
					}
				}
			}
		}
		
		bool step3() {
			short iter = 0;
			for (short i = 0; i < num_columns; i++) {
				if (column_starred[i]) {
					column_cov[i] = true;
				}
			}
			for (short i = 0; i < num_columns; i++) {
				if (column_cov[i]) {
					iter++;
				}
			}
			if (iter == num_rows) {
				return true;
			} else
				return step4();
		}

		bool step4() {
			short smallest = 0;
			for (short i = 0; i < num_rows; i++) {
				if (!row_cov[i]) {
					while (smallest == 0) {
						smallest = cell_array[i][0].weight;
						if (smallest == 0) {
							if (i < num_rows-1)
								i++;
							else
								break;
						}
					}

					for (short j = 0; j < num_columns; j++) {
						if (!column_cov[j] && !row_cov[i] && cell_array[i][j].weight == 0 && !row_starred[i]) {
							cell_array[i][j].primed = true;
							return step5(i, j);
						} else if (!column_cov[j] && !row_cov[i] && cell_array[i][j].weight == 0) {
							cell_array[i][j].primed = true;
							row_cov[i] = true;
							column_cov[find_star_row(i)] = false;
							i = 0;
							j = 0;
						}else if(!column_cov[j] && cell_array[i][j].weight != 0 &&\
									cell_array[i][j].weight < smallest) {
							smallest = cell_array[i][j].weight;
						}
					}
				}
			}
			return step6(smallest);
		}

		bool step5(short r, short c) {
			bool done = false;
			bool looking_for_star = true;
			short a;
			while (!done) {
				switch (looking_for_star) {
					case true:
						a = r;
						if (!column_starred[c]) {
							cell_array[r][c].primed = false;
							cell_array[r][c].starred = true;
							row_starred[r] = true;
							done = true;
						} else {
							r = find_star_column(c);
							cell_array[a][c].primed = false;
							cell_array[a][c].starred = true;
							row_starred[a] = true;
							looking_for_star = false;
						}
						column_starred[c] = true;
						break;
					case false:
						cell_array[r][c].primed = false;
						cell_array[r][c].starred = false;
						row_starred[r] = false;
						c = find_prime_row(r);
						looking_for_star = true;
						break;
				}
			}
			for (short i = 0; i < num_rows; i++) {
				for (short j = 0; j < num_columns; j++) {
					cell_array[i][j].primed = false;
				}
				row_cov[i] = false;
			}

			for (short i = 0; i < num_columns; i++) {
				column_cov[i] = false;
			}
			return step3();
		}

		bool step6(short sub) {
			for (short i = 0; i < num_rows; i++) {
				for (short j = 0; j < num_columns; j++) {
					if (!row_cov[i] && !column_cov[j]) {
						cell_array[i][j].weight -= sub;
					} else if (row_cov[i] && column_cov[j]) {
						cell_array[i][j].weight += sub;
					}
				}
			}
			return step4();
		}
		
		//The function that will call each of step of Munkres' algorithm in turn
		//We're using this since multiple functions use the algorithm
		bool find_a_matching(void) {
			step1();
			step2();
			return step3();
		}
};


void analogous_code(const string& word, string& code) {
	code.clear();
	string::const_iterator w = word.begin();
	map<char, short> hash;
	map<char, short>::iterator it;
	while(w != word.end()) {
		it = hash.find(*w);
		if(it == hash.end()) {
			pair<char, short>p(*w, 1);
			hash.insert(hash.end(), p);
		} else {
			it->second++;
		}
		w++;
	}
	for(short i =0; i < word.size(); i++) {
		code += (char)((short)hash[word[i]]+(short)'0');
	}
	sort(code.begin(), code.end(), greater<char>());
}

/*
   ones - sum of all ones thrown
   twos - sum of all twos thrown
   threes - sum of all threes thrown
   fours - sum of all fours thrown
   fives - sum of all fives thrown
   sixes - sum of all sixes thrown
   chance - sum of all dice
   three of a kind - sum of all dice, provided at least three have same value
   four of a kind - sum of all dice, provided at least four have same value
   five of a kind - 50 points, provided all five dice have same value
   short straight - 25 points, provided four of the dice form a sequence (that is, 1,2,3,4 or 2,3,4,5 or 3,4,5,6)
   long straight - 35 points, provided all dice form a sequence (1,2,3,4,5 or 2,3,4,5,6)
   full house -40 points, provided three of the dice are equal and the other two dice are also equal.
   (for example, 2,2,5,5,5)
   */
short sum_all(const string& dices) {
	return (accumulate(dices.begin(), dices.end(), 0) - (48*5));
}

short face(const string& dices, char head) {
	short score = 0;	
	size_t it = dices.find(head);
	while(it < dices.size() && dices.at(it) == head) {
		score+=(head-48);
		it++;
	}
	return score;
}

short three_of_a_kind(const string& dices, const string& code) {
	if(code == "33322" || code == "33311" || code == "44441" || code == "55555") {
		return sum_all(dices);
	} else {
		return 0;
	}	
}

short four_of_a_kind(const string& dices, const string& code) {
	if(code == "44441" || code == "55555") {
		return sum_all(dices);
	} else {
		return 0;	
	}	
}

short five_of_a_kind(const string& code) {
	return ((code == "55555") ? 50 : 0);	
}

short full_house(const string& code) {
	return ((code == "33322" || code == "55555") ? 40 : 0);	
}

short short_straight(const string& dices, const string& code) {
	if(code == "22111" || code == "11111") {
		char start = dices[0]; 
		if(start-1 != dices[1]) {
			start = dices[1];
		}
		short count = 3;
		while(count-- > 0) {
			if(dices.find(--start) == string::npos)
				return 0;
		}
		return 25;
	}
	return 0;
}

short long_straight(const string& dices) {
	return ((dices == "65432") || (dices == "54321") ? 35 : 0);	
}

enum {
	CHOSEN = 0,
	FACE1 = 1,		
	FACE2 = 2,		
	FACE3 = 3,		
	FACE4 = 4,		
	FACE5 = 5,		
	FACE6 = 6,
	CHANCE = 7,
	K3 = 8,
	K4 = 9,
	K5 = 10,
	SS = 11,
	LS = 12,
	FULL = 13,
	BONUS = 14,
	SUM = 15
};

void get_category(const string& dices, Category& score_list) {
	string code;
	analogous_code(dices, code);
	for(short i = 1; i <= 13; i++) {
		short score = 0;
		switch(i) {
			case FACE1:
				score = face(dices, '1');
				break;
			case FACE2:
				score = face(dices, '2');
				break;
			case FACE3:
				score = face(dices, '3');
				break;
			case FACE4:
				score = face(dices, '4');
				break;
			case FACE5:
				score = face(dices, '5');
				break;
			case FACE6:
				score = face(dices, '6');
				break;
			case CHANCE:
				score = sum_all(dices);
				break;
			case K3:
				score = three_of_a_kind(dices, code);
				break;
			case K4:
				score = four_of_a_kind(dices, code);
				break;
			case K5:
				score = five_of_a_kind(code);
				break;
			case FULL:
				score = full_house(code);
				break;
			case SS:
				score = short_straight(dices, code);
				break;
			case LS:
				score = long_straight(dices);
				break;
			default:
				break;
		}
		score_list.push_back(score);
	}
}

void read_game(Game& game) {
	short throw_count = 0;
	while(++throw_count <= 13) {
		oss.clear();
		string line, round;
		getline(cin, line);
		oss << line;
		copy(iIterator(oss), iIterator(), back_inserter(round));
		if(round.empty() == false) {
			sort(round.begin(), round.end(), greater<char>());
			Category score_list;
			score_list.push_back(0);
			get_category(round, score_list);
			game.insert(game.end(), make_pair(round, score_list));
		}
	}
}

short Bonus_Sum() {
	return accumulate(Scores, Scores+6, 0);	
}

short isBonus() {
	return accumulate(Scores, Scores+6, 0) >= bonus_score ? bonus_points : 0;	
}

short Total(short* sc) {
	return accumulate(sc, sc+14, 0);	
}


void print_game(const Game& game) {
	Game::const_iterator it = game.begin();
	cout <<endl;
	while(it != game.end()) {
		cout << it->first << " : ";
		copy(it->second.begin(), it->second.end(), ostream_iterator<short>(cout, "\t"));
		cout <<endl;
		it++;	
	}
	cout <<endl;
}

void choose_bet(Game& game, short bet) {
	Game::iterator it = game.begin();
	Game::iterator best = game.end();
	while(it != game.end()) {
		if(best == game.end() && it->second[CHOSEN] == 0) {
			best = it;	
		} else if(best != game.end() && it->second[bet] > best->second[bet] && it->second[CHOSEN] ==0) {
			best = it;
		} else if(best != game.end() && it->second[bet] == best->second[bet] &&\
				it->second[CHOSEN] ==0 && it->second[CHANCE] < best->second[CHANCE]) {
			best = it;
		}
		it++;
	}
	if(best != game.end() && best->second[bet] != 0) {
		best->second[CHOSEN] = bet;
		Scores[bet-1] = best->second[bet];
	}	
}

void clear_bets(Game& game, short start=FACE1, short end=FACE6) {
	Game::iterator it = game.begin();
	while(it != game.end()) {
		if(it->second[CHOSEN] >= start && it->second[CHOSEN] <= end) {
			Scores[it->second[CHOSEN]-1] = 0;
			it->second[CHOSEN] = CHOSEN;
		}
		it++;
	}
}

short hungarian_assignment(const vector<Vshort>& hash, vector<ordered_pair>& positions) {
	munkres munk;
	munk.load_weights(hash);
	return munk.assign(positions);
}

void update_score_from_position(const vector<Game::iterator>& column, const vector<ordered_pair>& positions) {
	for(short i = 0; i < FACE6 && i < positions.size(); ++i) {
		column[positions[i].second]->second[0] = FACE1+i;
		Scores[FACE1+i-1] = column[positions[i].second]->second[FACE1+i];
	}
}

short current_sum(const vector<Game::iterator>& column, const vector<ordered_pair>& positions) {
	short sum = 0;
	for(short i = 0; i < FACE6 && i < positions.size(); ++i) 
		sum += column[positions[i].second]->second[FACE1+i];
	return sum;	
}

void search_hungarian_match(const vector<Vshort>& hash,\
		const vector<Game::iterator>& column,\
		vector<ordered_pair>& in, bool max = false)
{
	hungarian_assignment(hash, in);
	short sum = current_sum(column, in);
	if(sum <= bonus_score || max == true) 
		return;
	short previous_sum = sum;
	vector<Vshort> rehash;
	short row, col;
	bool found = false;
	bool again = true;
	vector<ordered_pair> out(in);
	while (found == false && again == true) {
		again = false;
		for(short i = 0; i < out.size(); i++) {
			rehash = hash;
			row = out[i].first;
			col = out[i].second;
			rehash[row][col] = max_score;
			hungarian_assignment(rehash, in);
			sum = current_sum(column, in);
			if(sum == bonus_score) {
				found = true;
				out = in;
				break;
			} else if(sum > bonus_score && sum < previous_sum) {
				out = in;
				previous_sum = sum;
				again = true;
				break;
			}
		}
	}
	in = out;
}

bool choose_face_bet(const vector<Vshort>& hash, const vector<Game::iterator>& column, bool max=false) {
	for(short i = 0; i < hash.size(); ++i) {
		copy(hash[i].begin(), hash[i].end(), ostream_iterator<short>(cout, " "));
		cout << endl;
	}
	vector<ordered_pair> out(hash.size());
	search_hungarian_match(hash, column, out, max);
	update_score_from_position(column, out);
	return isBonus() != 0;
}

bool choose_face_bet(Game & game, short include_chance=false, bool max=false) {
	short rows = FACE6+include_chance;
	vector<Vshort> transpose_hash(rows);
	vector<Game::iterator> column;
	Game::iterator it = game.begin();
	while(it != game.end()) {
		if(it->second[CHOSEN] == CHOSEN) {
			for(short i = 0; i < rows; i++)
				transpose_hash[i].push_back(max_score - *(it->second.begin()+1+i));
			column.push_back(it);
		}
		it++;
	}
	// Make matrix N*N
	for(short i = rows; i < transpose_hash[0].size(); ++i) 
		transpose_hash.push_back(Vshort(transpose_hash[0].size(), max_score));
	return choose_face_bet(transpose_hash, column, max);
}

// Min Score 5
// Max Score 375 - > 11111, 22222, 33333, 44444, 55555, 66666, 66666, 
// 66666, 66666, *(66666, 66666), *(12345, 12345)
// Oreder - SS, LS, 5k, 6s, 5s , 4s, 3s, 2s, 1s, 4k, 3k, FULL, C 
void Yahtzee(Game& game) {
	short prev_scores[15];
	if(choose_face_bet(game) == true) { 
		choose_bet(game, LS);
		choose_bet(game, SS);
		choose_bet(game, K5);
		choose_bet(game, FULL);
		choose_bet(game, K4);
		choose_bet(game, K3);
		choose_bet(game, CHANCE);
		Scores[BONUS-1] = bonus_points;
		
		memcpy(prev_scores, Scores, sizeof(short)*15);
		clear_bets(game, FACE1, FULL);
		Scores[BONUS-1] = 0;

		choose_bet(game, LS);
		choose_bet(game, SS);
		choose_bet(game, K5);
		choose_bet(game, FULL);
		if(choose_face_bet(game, true, true) == true) {
			Scores[BONUS-1] = bonus_points;
		} 
		choose_bet(game, K4);
		choose_bet(game, K3);
		choose_bet(game, CHANCE);

		if (Total(Scores) < Total(prev_scores)){
			memcpy(Scores, prev_scores, sizeof(short)*15);
		}

	} else {
		clear_bets(game);
		choose_bet(game, LS);
		choose_bet(game, SS);
		choose_bet(game, K5);
		choose_bet(game, FULL);
		choose_bet(game, K4);
		choose_bet(game, K3);
		choose_face_bet(game, true);
		choose_bet(game, CHANCE);
		
		memcpy(prev_scores, Scores, sizeof(short)*15);
		clear_bets(game, FACE1, K4);
		
		choose_face_bet(game);
		choose_bet(game, K4);
		choose_bet(game, K3);
		choose_bet(game, CHANCE);

		if (Total(Scores) < Total(prev_scores)){
			memcpy(Scores, prev_scores, sizeof(short)*15);
		}

	}
	Scores[SUM-1] = Total(Scores);
}

int main() {
	while(cin.eof() == false) {
		memset(Scores, 0, sizeof(short)*15);
		Game game;
		read_game(game);
		if(game.size() == 13) {
			Yahtzee(game);
			copy(Scores, Scores+14, ostream_iterator<short>(cout, " "));
			cout << Scores[14] << endl;
		}
		//print_game(game);
	}
	return 0;	
}
